import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;
import java.util.Arrays;
import java.util.Collections;

public class Main {
	public static int refreshRate = 40;
	private static Robot r;
	private static MoveGesture moveGesture;
	private static Identificator identificator;
	private static CheckerBoard checkerBoard;
	private static Depot depot;
	private static Toolkit keyLogger;
	
	public static void main(String[] args) throws Exception {
		r = new Robot();
		moveGesture = new MoveGesture(r);
		identificator = new Identificator(r);
		checkerBoard = new CheckerBoard();
		depot = new Depot();
		keyLogger = Toolkit.getDefaultToolkit();
		
		boolean onceIsEnough = false;
		boolean ending = false;
		for (;;) {
			Thread.sleep(refreshRate / 5);
			if (keyLogger.getLockingKeyState(KeyEvent.VK_CAPS_LOCK) && !checkerBoard.isFull()) {
				onceIsEnough = true;
				Piece nextPiece = new Piece(identificator.identifie(0, 0, 4, 4));
				if (nextPiece.getSize() == 0) {
					moveGesture.takeNextPiece();
				} else {
					Candidate candR0 = checkerBoard.bestPositionFor(nextPiece);
					Candidate candR1 = checkerBoard.bestPositionFor(candR0.piece.rotation3PiOver2());
					Candidate candR2 = checkerBoard.bestPositionFor(candR1.piece.rotation3PiOver2());
					Candidate candR3 = checkerBoard.bestPositionFor(candR2.piece.rotation3PiOver2());
					Candidate winner = Collections.min(Arrays.asList(new Candidate[] { candR0, candR1, candR2, candR3 }));
					if (nextPiece.getSize() == 1 && candR0.dist != -4 && !depot.isFull()) {
						moveGesture.select(nextPiece.xSelect, nextPiece.ySelect);
						int[] coords = depot.addPiece();
						moveGesture.putAt(Piece.unitPiece, coords[0], coords[1] + 5);
					} else if (winner.dist == Integer.MAX_VALUE || (ending && nextPiece.getSize() == 1)) {
						ending = true;
						end();
					} else {
						moveGesture.select(nextPiece.xSelect, nextPiece.ySelect);
						moveGesture.rotate(winner.piece.rotationNeeded);
						putThePiece(winner);
					}
					System.out.println("\n\n\n\n\n\n" + depot);
					System.out.println("\n\n\n\n\n" + checkerBoard);
				}
			} else {
				if (onceIsEnough) {
					onceIsEnough = false;
					ending = false;
					checkerBoard.clear();
					System.gc();
					Thread.sleep(3000);
				}
			}
		}
		//	refreshRate = 100;
		//	boolean state = false;
		//	DualDepotDirty d = new DualDepotDirty();
		//	for (int i = 0; i < 3; i++) {
		//		d.addPiece();
		//	}
		//	for (;;) {
		//		Thread.sleep(10);
		//		if (state != Toolkit.getDefaultToolkit().getLockingKeyState(KeyEvent.VK_CAPS_LOCK)) {
		//			state = !state;
		//			int[] coords = d.removePiece();
		//			moveGesture.select(coords[0], coords[1]);
		//			Candidate winner = checkerBoard.bestPositionFor(Piece.dualPiece);
		//			moveGesture.putAt(winner.piece, winner.x + 6, winner.y);
		//			checkerBoard.add(winner);
		//			System.out.println("\n\n" + d);
		//			System.out.println("\n\n" + checkerBoard);	
		//		}
		//	}
	}
	
	private static void putThePiece(Candidate winner) {
		CheckerBoard backup = checkerBoard.clone();
		moveGesture.putAt(winner.piece, winner.x + 5, winner.y);
		checkerBoard.add(winner);
		
		moveGesture.moveOutForSceenShot();
		boolean[][] snapShot = identificator.identifie(5, 0, 13, 13);
		if (!BooleanArrayTools.equals(snapShot, checkerBoard.getShape())) {
			if (!BooleanArrayTools.equals(backup.getShape(), snapShot)) {
				CheckerBoard theFinal = backup;
				boolean[][] current = snapShot;
				while (!BooleanArrayTools.equals(theFinal.getShape(), current)) {
					int[] coords = BooleanArrayTools.firstDif(theFinal.getShape(), current);
					if (current[coords[1]][coords[0]]) {
						moveGesture.select(coords[0] + 5, coords[1]);
						if (new Board(identificator.identifie(0, 0, 4, 4)).getSize() == 0) {
							moveGesture.putToIdentificationPlace();
						} else {
							moveGesture.destroyPiece();
						}
						current = identificator.identifie(5, 0, 13, 13);
					} else {
						theFinal.getShape()[coords[1]][coords[0]] = false;
					}
				}
				checkerBoard = theFinal;
			} else {
				// Wrong identification or wrong position
				if (new Board(identificator.identifie(0, 0, 4, 4)).getSize() == 0) {
					moveGesture.putToIdentificationPlace();
				}
				checkerBoard = backup;
			}
		}
	}
	private static void end() {
		if (canBeSimplySolved()) {
			while (!checkerBoard.isFull()) {
				Candidate winner = checkerBoard.bestPositionFor(Piece.unitPiece);
				int[] coords = depot.removePiece();
				moveGesture.select(coords[0], coords[1] + 5);
				putThePiece(winner);
			}
		} else {
			Piece toDestroy = new Piece(identificator.identifie(0, 0, 4, 4));
			moveGesture.select(toDestroy.xSelect, toDestroy.ySelect);
			moveGesture.destroyPiece();
		}
	}
	
	private static boolean canBeSimplySolved() {
		if (depot.getSize() < (CheckerBoard.totalCapacity - checkerBoard.getSize())) {
			return false;
		}
		CheckerBoard simulation = checkerBoard.clone();
		while (!simulation.isFull()) {
			Candidate winner = simulation.bestPositionFor(Piece.unitPiece);
			if (winner.dist == Integer.MAX_VALUE) {
				return false;
			}
			simulation.add(winner);
		}
		return true;
	}
}